﻿using System.CodeDom;
using System.ComponentModel;
using System.Linq;
using AopCore;
using Roslyn.Compilers.CSharp;

namespace WeaverCustomTool
{
    public struct INotifyPropertyChangedDeclaration
    {
        private CodeMemberProperty property;

        public INotifyPropertyChangedDeclaration(CodeMemberProperty property)
        {
            this.property = property;
        }

        /// <summary>
        /// Implements the INotify property changed pattern in setter.
        /// </summary>
        public void ImplementINotifyPropertyChanged(CodeStatementCollection codeStatmentStream)
        {
            var propertyChangedReference = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "PropertyChanged");
            var propertyChangedVariableReference = new CodeVariableReferenceExpression("propertyChanged");

            var storePropertyChangedStatment = new CodeVariableDeclarationStatement(
                typeof(PropertyChangedEventHandler),
                "propertyChanged",
                propertyChangedReference);

            var raiseEventStatment = new CodeDelegateInvokeExpression(
                propertyChangedVariableReference,
                new CodeThisReferenceExpression(),
                new CodeObjectCreateExpression(
                    typeof(PropertyChangedEventArgs),
                    new CodePrimitiveExpression(property.Name)));

            var eventNotNullCondition = new CodeBinaryOperatorExpression(
                propertyChangedVariableReference,
                CodeBinaryOperatorType.IdentityInequality,
                new CodePrimitiveExpression(null));

            var trueStatment = new CodeStatement[] {new CodeExpressionStatement(raiseEventStatment)};
            var eventNotNullconditionStatment = new CodeConditionStatement(eventNotNullCondition, trueStatment);

            codeStatmentStream.Add(storePropertyChangedStatment);
            codeStatmentStream.Add(eventNotNullconditionStatment);   
        }

        public bool CheckIfInotifyPropertyChangedImplementationIsRequiredFromInterface(InterfaceDeclarationSyntax @interface)
        {
            return @interface.DescendantNodes().OfType<PropertyDeclarationSyntax>().Any(p => p.ManageAttributes().AnyOfType<NotifyPropertyChangedAttribute>());
        }
    }
}
